﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Geometry
{
	public class Circle
	{
		private GeomVector2 center;
		private float radius;

		public GeomVector2 Center
		{
			get { return center; }
		}

		public float Radius
		{
			get { return radius; }
		}

		public Circle(GeomVector2 center, float radius)
		{
			this.center = center;
			this.radius = radius;
		}

		// Return the points counterclockwise starting from pointsIncluded[0]
		public List<GeomVector2> getPolygonalPoints(int amountPoints, List<GeomVector2> pointsIncluded)
		{
			List<GeomVector2> points = new List<GeomVector2>();
			float initialAngle = 0;

			if (pointsIncluded.Count > 0)
			{
				initialAngle = (float)(Math.Acos((pointsIncluded[0].X - center.X) / radius) * amountPoints);	// k = 0
				if (pointsIncluded[0].Y - center.Y < 0) initialAngle = (float)(2 * Math.PI) - initialAngle;
			}
			else {
				initialAngle = 0;
			}
			
			List<GeomVector2> pointsIncludedSorted = new List<GeomVector2>(pointsIncluded);
			if (pointsIncludedSorted.Count > 0) pointsIncludedSorted.RemoveAt(0);	// This first point is already included
			pointsIncludedSorted.Sort(
				delegate(GeomVector2 pointA, GeomVector2 pointB) 
				{
					float angleA = (getAngle(pointsIncluded[0]) > getAngle(pointA)) ? getAngle(pointA) + (float)(2 * Math.PI) : getAngle(pointA);
					float angleB = (getAngle(pointsIncluded[0]) > getAngle(pointB)) ? getAngle(pointB) + (float)(2 * Math.PI) : getAngle(pointB);

					return angleA.CompareTo(angleB); 
				});

			float firstAngle = initialAngle / amountPoints;

			for (int i = 0; i < amountPoints; i++)
			{
				float angle = (initialAngle + 2 * i * (float)Math.PI) / amountPoints;

				float includePointAngle = 0;
				if (pointsIncludedSorted.Count > 0)
				{
					if (getAngle(pointsIncluded[0]) > getAngle(pointsIncludedSorted[0]))
					{
						includePointAngle = getAngle(pointsIncludedSorted[0]) + (float)(2 * Math.PI);
					}
					else
					{
						includePointAngle = getAngle(pointsIncludedSorted[0]);
					}

				}

				while (pointsIncludedSorted.Count > 0 && includePointAngle < angle)
				{
					points.Add(pointsIncludedSorted[0]);
					pointsIncludedSorted.RemoveAt(0);
				}

				if (pointsIncludedSorted.Count > 0 && getAngle(pointsIncludedSorted[0]) == angle) 
					pointsIncludedSorted.RemoveAt(0);

				float Xvalue = (float)(Math.Cos(angle) * radius + center.X);
				float Yvalue = (float)(Math.Sin(angle) * radius + center.Y);

				points.Add(new GeomVector2(Xvalue, Yvalue));

			}

			return points;
		}

		public float getAngle(GeomVector2 point)
		{
			float angle = (float)(Math.Acos((point.X - center.X)/radius));
			if (point.Y - center.Y < 0) angle = (float)(2 * Math.PI) - angle;

			return angle;
		}

		public bool containsPoint(GeomVector2 point)
		{
			if (GeomVector2.Distance(point, center) <= radius) return true;
			else return false;
		}

		public List<GeomVector2> getIntersectionPoints(Rect rect)
		{
			return Intersection.getIntersection(rect, this);
		}
	}
}
